package com.jiashn.minio.utils;

import com.fasterxml.jackson.databind.util.JSONPObject;
import com.google.common.collect.Multimap;
import com.jiashn.minio.config.PearMinioClient;
import io.minio.*;
import io.minio.http.Method;
import io.minio.messages.Part;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.InputStream;
import java.util.Date;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * @author: jiangjs
 * @description: minio分片上传工具
 * @date: 2023/10/24 14:22
 **/
@Component
@Slf4j
public class PearMinioHelper {

    @Resource
    private PearMinioClient pearMinioClient;

    private void existAndCreateBucket(String bucketName){
        try {
            boolean exists = pearMinioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
            if (!exists){
                pearMinioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
            }
        } catch (Exception e) {
            log.error("验证并创建桶失败："+e.getMessage());
            e.printStackTrace();
        }
    }

    public JSONPObject uploadSingleFile(MultipartFile file, String bucketName){
        existAndCreateBucket(bucketName);
        String pearFileName = this.generatePearFileName(file.getOriginalFilename());
        try (InputStream ism = file.getInputStream()){
            pearMinioClient.putObject(PutObjectArgs.builder().bucket(bucketName)
                    .object(pearFileName)
                    .stream(ism,ism.available(),-1)
                    .build());
            return new JSONPObject(pearFileName,file.getOriginalFilename());
        }catch (Exception e){
            log.error("验证并创建桶失败："+e.getMessage());
            e.printStackTrace();
        }
        return null;
    };

    /**
     * 获取分片的uploadId
     * @param bucketName 桶名称
     * @param region 区域
     * @param objectName 对象名称
     * @param headers 头部信息
     * @param extraQueryParams 额外查询信息，
     * @return 返回创建uploadId对象
     */
    public CreateMultipartUploadResponse createUploadId(String bucketName, String region, String objectName, Multimap<String, String> headers, Multimap<String, String> extraQueryParams){
        existAndCreateBucket(bucketName);
        try {
            return pearMinioClient.createMultipartUpload(bucketName, region, objectName, headers, extraQueryParams);
        } catch (Exception e) {
            log.error("获取上传uploadId出错："+e.getMessage());
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 获取分片信息
     * @param bucketName 桶
     * @param region 区域
     * @param objectName 对象名称
     * @param maxParts 最大部分
     * @param partNumberMarker 部分编号标记
     * @param uploadId 上传部分Id
     * @param extraHeaders 额外头部信息
     * @param extraQueryParams 额外查询参数
     * @return 返回分片信息
     */
    public ListPartsResponse listMultipart(String bucketName,String region,String objectName,Integer maxParts,Integer partNumberMarker,
                                           String uploadId, Multimap<String, String> extraHeaders, Multimap<String, String> extraQueryParams){
        existAndCreateBucket(bucketName);
        try {
            return pearMinioClient.listMultipart(bucketName, region, objectName, maxParts, partNumberMarker, uploadId, extraHeaders, extraQueryParams);
        }catch (Exception e) {
            log.error("获取上传："+e.getMessage());
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 获取预上传的url
     * @param bucketName 桶
     * @param objectName 对象名称
     * @param queryParams 查询参数
     * @return url
     */
    public String prepareUploadObjectUrl(String bucketName,String objectName, Map<String, String> queryParams){
        existAndCreateBucket(bucketName);
        try {
            return pearMinioClient.getPresignedObjectUrl(
                    GetPresignedObjectUrlArgs.builder()
                            .method(Method.PUT)
                            .bucket(bucketName)
                            .object(objectName)
                            .expiry(1, TimeUnit.DAYS)
                            .extraQueryParams(queryParams)
                            .build());
        } catch (Exception e) {
            log.error("查询分片失败", e);
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 合并分片
     * @param bucketName 桶
     * @param region 区域
     * @param objectName 对象名称
     * @param uploadId 上传Id
     * @param parts 部分数组
     * @param extraHeaders 额外头部信息
     * @param extraQueryParams 额外查询参数
     * @return 返回合并结果
     */
    public ObjectWriteResponse completeMultipartUpload(String bucketName, String region, String objectName, String uploadId, Part[] parts, Multimap<String, String> extraHeaders, Multimap<String, String> extraQueryParams) {
        existAndCreateBucket(bucketName);
        try {
            return pearMinioClient.completeMultipartUpload(bucketName, region, objectName, uploadId, parts, extraHeaders, extraQueryParams);
        } catch (Exception e) {
            log.error("合并分片：", e);
            e.printStackTrace();
        }
        return null;
    }

    private String generatePearFileName(String fileName){
       return  "files"+ DateFormatUtils.format(new Date(),"yyyy-MM-dd") + String.valueOf(UUID.randomUUID()).replace("-","") + fileName;
    }
}
